#include "CSession.h"
#include "CServer.h"
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/uuid_io.hpp>
#include "MsgNode.h"
#include "const.h"
#include "LogicSys.h"

CSession::CSession(boost::asio::io_context& ioc, CServer* server):_socket(ioc),_server(server),_b_stop(false)
{
	boost::uuids::uuid uuid = boost::uuids::random_generator()();
	_session_id = boost::uuids::to_string(uuid);
	_recv_head_node = std::make_shared<MsgNode>(HEAD_TOTAL_LEN);
}

CSession::~CSession()
{
	std::cout << "~CSession" << std::endl;
}


std::string CSession::GetUuid()
{
	return _session_id;
}

void CSession::SetUserId(int uid)
{
	_user_id = uid;
}

int CSession::GetUserId()
{
	return _user_id;
}

boost::asio::ip::tcp::socket& CSession::GetSocket()
{
	return _socket;
}

void CSession::Start()
{
	boost::asio::async_read(_socket,boost::asio::buffer(_recv_head_node->_data,HEAD_TOTAL_LEN),std::bind(&CSession::HandleReadHead,this,std::placeholders::_1,std::placeholders::_2,shared_from_this()));
}

void CSession::Close()
{
	_socket.close();
	_b_stop = true;
}

void CSession::Send(std::string msg, short max_len, short msg_id)
{
	/*Send(msg.c_str(), max_len, msg_id);*/
	std::lock_guard<std::mutex> lock(_mtx);
	int que_size = _send_que.size();
	if (que_size > MAX_SENTQUE)
	{
		std::cout << "session:" << _session_id << "send que full;MAXQUE_SIZE=" << MAX_SENTQUE << std::endl;
		return;
	}

	_send_que.push(std::make_shared<SendNode>(msg.c_str(), msg.length(), msg_id));
	if (que_size > 0)
	{
		return;
	}

	auto& msg_node = _send_que.front();
	boost::asio::async_write(_socket, boost::asio::buffer(msg_node->_data, msg_node->_len), std::bind(&CSession::HandleWrite, this, std::placeholders::_1, shared_from_this()));
}

void CSession::Send(char* msg, short max_len, short msg_id)
{
	std::lock_guard<std::mutex> lock(_mtx);
	size_t que_size = _send_que.size();
	if (que_size > MAX_SENTQUE)
	{
		std::cout << "session:" << _session_id << "send que full;MAXQUE_SIZE="<<MAX_SENTQUE << std::endl;
		return;
	}
	_send_que.push(std::make_shared<SendNode>(msg, max_len, msg_id));

	if (que_size > 0)
	{
		return;
	}

	auto& msg_node = _send_que.front();
	boost::asio::async_write(_socket, boost::asio::buffer(msg_node->_data, msg_node->_len), std::bind(&CSession::HandleWrite, this, std::placeholders::_1, shared_from_this()));

}

void CSession::HandleReadHead(const boost::system::error_code& ec, size_t bytes_transferred, std::shared_ptr<CSession>)
{
	if (ec)
	{
		std::cerr << "HandleReadHead Err:" << ec.message() << std::endl;
		return;
	}
	short data_id = 0;
	short data_len = 0;
	memcpy(&data_id, _recv_head_node->_data, HEAD_ID_LEN);
	data_id = boost::asio::detail::socket_ops::network_to_host_short(data_id);
	std::cout << "data id :" << data_id << std::endl;
	memcpy(&data_len, _recv_head_node->_data + HEAD_ID_LEN, HEAD_DATA_LEN);
	data_len = boost::asio::detail::socket_ops::network_to_host_short(data_len);
	std::cout << "data len :" << data_len << std::endl;
	if (data_id > MAX_LEN|| data_len>MAX_LEN)
	{
		std::cerr << "invalid data id/len" << std::endl;
		_server->ClearSession(_session_id);
		return;
	}
	_recv_msg_node = std::make_shared<RecvNode>(data_len, data_id);
	boost::asio::async_read(_socket, boost::asio::buffer(_recv_msg_node->_data, data_len), std::bind(&CSession::HandleReadMsg, this, std::placeholders::_1, std::placeholders::_2, shared_from_this()));

}

void CSession::HandleReadMsg(const boost::system::error_code& ec, size_t bytes_transferred, std::shared_ptr<CSession> session)
{
	if (ec) 
	{
		std::cerr << "HandleReadMsg Err:" << ec.message() << std::endl;
		return;
	}
	std::cout << std::string(_recv_msg_node->_data, _recv_msg_node->_len);
	LogicSys::GetInst().PostMsgToQue(std::make_shared<LogicNode>(session, _recv_msg_node));
	_recv_head_node->Clear();
	boost::asio::async_read(_socket, boost::asio::buffer(_recv_head_node->_data, HEAD_TOTAL_LEN), std::bind(&CSession::HandleReadHead, this, std::placeholders::_1, std::placeholders::_2, shared_from_this()));





}

void CSession::HandleWrite(const boost::system::error_code& ec, std::shared_ptr<CSession>)
{
	try
	{
		if (ec)
		{
			std::cerr << "HandleWrite Exception:" << ec.message() << std::endl;
			_server->ClearSession(_session_id);
			Close();
		}
		std::lock_guard<std::mutex> lock(_mtx);
		_send_que.pop();
		if (!_send_que.empty())
		{
			auto& msgnode = _send_que.front();
			boost::asio::async_write(_socket, boost::asio::buffer(msgnode->_data, msgnode->_len), std::bind(&CSession::HandleWrite, this, std::placeholders::_1, shared_from_this()));
		}
	}
	catch (std::exception& e)
	{
		std::cerr << "HandleWrite Err:" << e.what() << std::endl;
	}
}

LogicNode::LogicNode(std::shared_ptr<CSession> session, std::shared_ptr<RecvNode> recv_node):_session(session),_recv_node(recv_node)
{

}
